#pragma once


#include <iostream>
#include <sstream>
#include <string>
#include <ctime>
#include <filesystem>
#include <fstream>
#include <mutex>
#include <memory>
#include <unistd.h>
// 编写日志系统

namespace Logspace
{
// 重置所有样式（必用，否则颜色会持续生效）
#define RESET "\033[0m"

// 前景色（文本颜色）
#define BLACK(text) "\033[30m" text RESET
#define RED(text) "\033[31m" text RESET
#define GREEN(text) "\033[32m" text RESET
#define YELLOW(text) "\033[33m" text RESET
#define BLUE(text) "\033[34m" text RESET
#define MAGENTA(text) "\033[35m" text RESET // 品红
#define CYAN(text) "\033[36m" text RESET    // 青色
#define WHITE(text) "\033[37m" text RESET
// 亮色调背景色
#define BG_LIGHT_BLACK(text) "\033[100m" text RESET
#define BG_LIGHT_RED(text) "\033[101m" text RESET
#define BG_LIGHT_GREEN(text) "\033[102m" text RESET
#define BG_LIGHT_YELLOW(text) "\033[103m" text RESET
#define BG_LIGHT_BLUE(text) "\033[104m" text RESET
#define BG_LIGHT_MAGENTA(text) "\033[105m" text RESET
#define BG_LIGHT_CYAN(text) "\033[106m" text RESET
#define BG_LIGHT_WHITE(text) "\033[107m" text RESET
// 文本样式
#define BOLD(text) "\033[1m" text RESET         // 加粗
#define UNDERLINE(text) "\033[4m" text RESET    // 下划线
#define BLINK(text) "\033[5m" text RESET        // 闪烁（部分终端不支持）
#define REVERSE(text) "\033[7m" text RESET      // 反色（前景色与背景色互换）

    enum Level
    {
        Info,
        Fatal,
        Warning,
        Debug,
        Error
    };

    // 时间字符串化
    std::string time_to_string()
    {
        time_t now = time(nullptr);
        std::tm *local_time = std::localtime(&now);

        char time_buf[100];
        snprintf(time_buf, sizeof(time_buf), "%04d-%02d-%02d %02d:%02d:%02d",
                 local_time->tm_year + 1900, local_time->tm_mon + 1, local_time->tm_mday,
                 local_time->tm_hour, local_time->tm_min, local_time->tm_sec);

        return time_buf;
    }

    // 将等级字符串化
    std::string level_to_string(Level level_)
    {
        switch (level_)
        {
        case Info:
            return "Info";
            break;
        case Fatal:
            return BLINK(BG_LIGHT_RED("Fatal"));
            break;
        case Warning:
            return BLUE("Warning");
            break;
        case Debug:
            return CYAN("Debug");
            break;
        case Error:
            return BLINK(BG_LIGHT_GREEN(BLACK("Error")));
            break;
        default:
            return WHITE("Unknow");
            break;
        }
    }

    class Output_Base
    {
    public:
        Output_Base() = default;
        virtual void OutputInfo(std::string) = 0;
    };

    class OutputToScreen : public Output_Base
    {
    public:
        void OutputInfo(std::string message)
        {
            mtx_.lock();
            std::cout << message << std::endl;
            mtx_.unlock();
        }
    private:
        std::mutex mtx_;
    };

    class OutputToFile : public Output_Base
    {
    public:
        OutputToFile(const std::string pathname , const std::string filename)
        {
            mtx_.lock();
            if(std::filesystem::exists(pathname) == false)
            {
                // 创建路径
                std::filesystem::create_directory(pathname);
            }
            completefilename = pathname + "/" + filename;
            mtx_.unlock();
        }

        void OutputInfo(std::string message)
        {
            mtx_.lock();
            std::ofstream ofs(completefilename.c_str() ,std::ios::app);
            ofs << message << std::endl;
            mtx_.unlock();
            ofs.close();
        }

    private:
        std::mutex mtx_;
        std::string completefilename;
    };

    class Logger
    {
    public:
        Logger()
        {
            output_ = std::make_unique<OutputToScreen>();
        }
        void UseConsoleStrategy()
        {
            output_ = std::make_unique<OutputToScreen>();
        }
        void UseFileStrategy(const std::string path , const std::string file )
        {
            output_ = std::make_unique<OutputToFile>(path , file);
        }

        class LogMessage
        {
        public:
            LogMessage(Level level , const char* infilename , const int line , Logger* plogger)
            :timestr_(time_to_string()) ,  levelstr_(level_to_string(level)) , pid_(getpid()),
                infilestr_(infilename) , line_(line) , plogger_(plogger)
            {
                // 对前面的基础信息进行整合
                std::ostringstream oss;
                oss << "[" << timestr_ << "]" 
                    << "[" << levelstr_ << "]"
                    << "[" << pid_ << "]"
                    << "[" << infilestr_ << "]"
                    << "[" << line_ << "] ";
                loginfo_ = oss.str() + " ";
            }   
            
            template<class T>
            LogMessage& operator<<(const T& message)
            {
                std::ostringstream ofs;
                ofs << message;
                loginfo_ += ofs.str();
                return *this;
            }
            ~LogMessage()
            {
                if(plogger_ && plogger_->output_)
                    plogger_->output_->OutputInfo(loginfo_);
            }
        private:
            std::string timestr_;       // 时间
            std::string levelstr_;      // 等级
            pid_t pid_;                 // PID
            std::string infilestr_;     // 信息对应的文件名
            unsigned int line_;         // 信息对应的行位置
            std::string loginfo_;       // 存储所有日志信息，将日志信息进行整合
            Logger* plogger_;
        };

        LogMessage operator()(Level level , const char* infilename , const int line )
        {
            return LogMessage(level , infilename , line , this);
        }

    private:
        std::unique_ptr<Output_Base> output_;
    };


    Logger _logger;
    #define Log(Level_) _logger(Level_ , __FILE__ , __LINE__)

    // 提供选择使⽤何种⽇志策略的⽅法
    #define ENABLE_CONSOLE_LOG_STRATEGY() _logger.UseConsoleStrategy()
    #define ENABLE_FILE_LOG_STRATEGY(path , file) _logger.UseFileStrategy(path , file)
};
